home *** CD-ROM | disk | FTP | other *** search
/ Team Palmtops 7 / Palmtops_numero07.iso / WinCE / SDKWindowsCE / HandHeldPCPro30 / sdk.exe / Jupiter SDK / data1.cab / MFC / include / afxtempl.h < prev    next >
Encoding:
C/C++ Source or Header  |  1999-02-19  |  47.3 KB  |  1,731 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #ifndef __AFXTEMPL_H__
  12. #define __AFXTEMPL_H__
  13.  
  14. #ifndef __AFXPLEX_H__
  15.     #include <afxplex_.h>
  16. #endif
  17.  
  18. #if defined(_WIN32_WCE)
  19.     #include "wcealt.h"
  20. #endif // _WIN32_WCE
  21. #ifdef _AFX_MINREBUILD
  22. #pragma component(minrebuild, off)
  23. #endif
  24. #ifndef _AFX_FULLTYPEINFO
  25. #pragma component(mintypeinfo, on)
  26. #endif
  27.  
  28. #ifdef _AFX_PACKING
  29. #pragma pack(push, _AFX_PACKING)
  30. #endif
  31.  
  32. #ifdef _DEBUG
  33. static char _szAfxTempl[] = "afxtempl.h";
  34. #undef THIS_FILE
  35. #define THIS_FILE _szAfxTempl
  36. #endif
  37.  
  38. #ifndef ALL_WARNINGS
  39. #pragma warning(disable: 4114)
  40. #endif
  41.  
  42. /////////////////////////////////////////////////////////////////////////////
  43. // global helpers (can be overridden)
  44.  
  45. #ifdef new
  46. #undef new
  47. #define _REDEF_NEW
  48. #endif
  49.  
  50. #ifndef _INC_NEW
  51.     #include <new.h>
  52. #endif
  53.  
  54. template<class TYPE>
  55. AFX_INLINE void AFXAPI ConstructElements(TYPE* pElements, int nCount)
  56. {
  57.     ASSERT(nCount == 0 ||
  58.         AfxIsValidAddress(pElements, nCount * sizeof(TYPE)));
  59.  
  60.     // first do bit-wise zero initialization
  61.     memset((void*)pElements, 0, nCount * sizeof(TYPE));
  62.  
  63.     // then call the constructor(s)
  64.     for (; nCount--; pElements++)
  65.         ::new((void*)pElements) TYPE;
  66. }
  67.  
  68. template<class TYPE>
  69. AFX_INLINE void AFXAPI DestructElements(TYPE* pElements, int nCount)
  70. {
  71.     ASSERT(nCount == 0 ||
  72.         AfxIsValidAddress(pElements, nCount * sizeof(TYPE)));
  73.  
  74.     // call the destructor(s)
  75.     for (; nCount--; pElements++)
  76.         pElements->~TYPE();
  77. }
  78.  
  79. template<class TYPE>
  80. AFX_INLINE void AFXAPI CopyElements(TYPE* pDest, const TYPE* pSrc, int nCount)
  81. {
  82.     ASSERT(nCount == 0 ||
  83.         AfxIsValidAddress(pDest, nCount * sizeof(TYPE)));
  84.     ASSERT(nCount == 0 ||
  85.         AfxIsValidAddress(pSrc, nCount * sizeof(TYPE)));
  86.  
  87.     // default is element-copy using assignment
  88.     while (nCount--)
  89.         *pDest++ = *pSrc++;
  90. }
  91.  
  92. template<class TYPE>
  93. void AFXAPI SerializeElements(CArchive& ar, TYPE* pElements, int nCount)
  94. {
  95.     ASSERT(nCount == 0 ||
  96.         AfxIsValidAddress(pElements, nCount * sizeof(TYPE)));
  97.  
  98.     // default is bit-wise read/write
  99.     if (ar.IsStoring())
  100.         ar.Write((void*)pElements, nCount * sizeof(TYPE));
  101.     else
  102.         ar.Read((void*)pElements, nCount * sizeof(TYPE));
  103. }
  104.  
  105. #ifdef _DEBUG
  106. template<class TYPE>
  107. void AFXAPI DumpElements(CDumpContext& dc, const TYPE* pElements, int nCount)
  108. {
  109.     ASSERT(nCount == 0 ||
  110.         AfxIsValidAddress(pElements, nCount * sizeof(TYPE), FALSE));
  111.     &dc; // not used
  112.     pElements;  // not used
  113.     nCount; // not used
  114.  
  115.     // default does nothing
  116. }
  117. #endif
  118.  
  119. template<class TYPE, class ARG_TYPE>
  120. BOOL AFXAPI CompareElements(const TYPE* pElement1, const ARG_TYPE* pElement2)
  121. {
  122.     ASSERT(AfxIsValidAddress(pElement1, sizeof(TYPE), FALSE));
  123.     ASSERT(AfxIsValidAddress(pElement2, sizeof(ARG_TYPE), FALSE));
  124.  
  125.     return *pElement1 == *pElement2;
  126. }
  127.  
  128. template<class ARG_KEY>
  129. AFX_INLINE UINT AFXAPI HashKey(ARG_KEY key)
  130. {
  131.     // default identity hash - works for most primitive values
  132.     return ((UINT)(void*)(DWORD)key) >> 4;
  133. }
  134.  
  135. // special versions for CString
  136. #if _MSC_VER >= 1100
  137. template<> void AFXAPI ConstructElements<CString> (CString* pElements, int nCount);
  138. template<> void AFXAPI DestructElements<CString> (CString* pElements, int nCount);
  139. template<> void AFXAPI CopyElements<CString> (CString* pDest, const CString* pSrc, int nCount);
  140. template<> void AFXAPI SerializeElements<CString> (CArchive& ar, CString* pElements, int nCount);
  141. #ifndef OLE2ANSI
  142. template<> UINT AFXAPI HashKey<LPCWSTR> (LPCWSTR key);
  143. #endif
  144. template<> UINT AFXAPI HashKey<LPCSTR> (LPCSTR key);
  145. #else // _MSC_VER >= 1100
  146. void AFXAPI ConstructElements(CString* pElements, int nCount);
  147. void AFXAPI DestructElements(CString* pElements, int nCount);
  148. void AFXAPI CopyElements(CString* pDest, const CString* pSrc, int nCount);
  149. void AFXAPI SerializeElements(CArchive& ar, CString* pElements, int nCount);
  150. #ifndef OLE2ANSI
  151. UINT AFXAPI HashKey(LPCWSTR key);
  152. #endif
  153. UINT AFXAPI HashKey(LPCSTR key);
  154. #endif // _MSC_VER >= 1100
  155.  
  156. // forward declarations
  157. class COleVariant;
  158. struct tagVARIANT;
  159.  
  160. // special versions for COleVariant
  161. #if _MSC_VER >= 1100
  162. template<> void AFXAPI ConstructElements<COleVariant> (COleVariant* pElements, int nCount);
  163. template<> void AFXAPI DestructElements<COleVariant> (COleVariant* pElements, int nCount);
  164. template<> void AFXAPI CopyElements<COleVariant> (COleVariant* pDest, const COleVariant* pSrc, int nCount);
  165. template<> void AFXAPI SerializeElements<COleVariant> (CArchive& ar, COleVariant* pElements, int nCount);
  166. #ifdef _DEBUG
  167. template<> void AFXAPI DumpElements<COleVariant> (CDumpContext& dc, const COleVariant* pElements, int nCount);
  168. #endif
  169. template<> UINT AFXAPI HashKey<const struct tagVARIANT&> (const struct tagVARIANT& var);
  170. #else // _MSC_VER >= 1100
  171. void AFXAPI ConstructElements(COleVariant* pElements, int nCount);
  172. void AFXAPI DestructElements(COleVariant* pElements, int nCount);
  173. void AFXAPI CopyElements(COleVariant* pDest, const COleVariant* pSrc, int nCount);
  174. void AFXAPI SerializeElements(CArchive& ar, COleVariant* pElements, int nCount);
  175. #ifdef _DEBUG
  176. void AFXAPI DumpElements(CDumpContext& dc, const COleVariant* pElements, int nCount);
  177. #endif
  178. UINT AFXAPI HashKey(const struct tagVARIANT& var);
  179. #endif // _MSC_VER >= 1100
  180.  
  181. #define new DEBUG_NEW
  182.  
  183. /////////////////////////////////////////////////////////////////////////////
  184. // CArray<TYPE, ARG_TYPE>
  185.  
  186. template<class TYPE, class ARG_TYPE>
  187. class CArray : public CObject
  188. {
  189. public:
  190. // Construction
  191.     CArray();
  192.  
  193. // Attributes
  194.     int GetSize() const;
  195.     int GetUpperBound() const;
  196.     void SetSize(int nNewSize, int nGrowBy = -1);
  197.  
  198. // Operations
  199.     // Clean up
  200.     void FreeExtra();
  201.     void RemoveAll();
  202.  
  203.     // Accessing elements
  204.     TYPE GetAt(int nIndex) const;
  205.     void SetAt(int nIndex, ARG_TYPE newElement);
  206.     TYPE& ElementAt(int nIndex);
  207.  
  208.     // Direct Access to the element data (may return NULL)
  209.     const TYPE* GetData() const;
  210.     TYPE* GetData();
  211.  
  212.     // Potentially growing the array
  213.     void SetAtGrow(int nIndex, ARG_TYPE newElement);
  214.     int Add(ARG_TYPE newElement);
  215.     int Append(const CArray& src);
  216.     void Copy(const CArray& src);
  217.  
  218.     // overloaded operator helpers
  219.     TYPE operator[](int nIndex) const;
  220.     TYPE& operator[](int nIndex);
  221.  
  222.     // Operations that move elements around
  223.     void InsertAt(int nIndex, ARG_TYPE newElement, int nCount = 1);
  224.     void RemoveAt(int nIndex, int nCount = 1);
  225.     void InsertAt(int nStartIndex, CArray* pNewArray);
  226.  
  227. // Implementation
  228. protected:
  229.     TYPE* m_pData;   // the actual array of data
  230.     int m_nSize;     // # of elements (upperBound - 1)
  231.     int m_nMaxSize;  // max allocated
  232.     int m_nGrowBy;   // grow amount
  233.  
  234. public:
  235.     ~CArray();
  236.     void Serialize(CArchive&);
  237. #ifdef _DEBUG
  238.     void Dump(CDumpContext&) const;
  239.     void AssertValid() const;
  240. #endif
  241. };
  242.  
  243. /////////////////////////////////////////////////////////////////////////////
  244. // CArray<TYPE, ARG_TYPE> inline functions
  245.  
  246. template<class TYPE, class ARG_TYPE>
  247. AFX_INLINE int CArray<TYPE, ARG_TYPE>::GetSize() const
  248.     { return m_nSize; }
  249. template<class TYPE, class ARG_TYPE>
  250. AFX_INLINE int CArray<TYPE, ARG_TYPE>::GetUpperBound() const
  251.     { return m_nSize-1; }
  252. template<class TYPE, class ARG_TYPE>
  253. AFX_INLINE void CArray<TYPE, ARG_TYPE>::RemoveAll()
  254.     { SetSize(0, -1); }
  255. template<class TYPE, class ARG_TYPE>
  256. AFX_INLINE TYPE CArray<TYPE, ARG_TYPE>::GetAt(int nIndex) const
  257.     { ASSERT(nIndex >= 0 && nIndex < m_nSize);
  258.         return m_pData[nIndex]; }
  259. template<class TYPE, class ARG_TYPE>
  260. AFX_INLINE void CArray<TYPE, ARG_TYPE>::SetAt(int nIndex, ARG_TYPE newElement)
  261.     { ASSERT(nIndex >= 0 && nIndex < m_nSize);
  262.         m_pData[nIndex] = newElement; }
  263. template<class TYPE, class ARG_TYPE>
  264. AFX_INLINE TYPE& CArray<TYPE, ARG_TYPE>::ElementAt(int nIndex)
  265.     { ASSERT(nIndex >= 0 && nIndex < m_nSize);
  266.         return m_pData[nIndex]; }
  267. template<class TYPE, class ARG_TYPE>
  268. AFX_INLINE const TYPE* CArray<TYPE, ARG_TYPE>::GetData() const
  269.     { return (const TYPE*)m_pData; }
  270. template<class TYPE, class ARG_TYPE>
  271. AFX_INLINE TYPE* CArray<TYPE, ARG_TYPE>::GetData()
  272.     { return (TYPE*)m_pData; }
  273. template<class TYPE, class ARG_TYPE>
  274. AFX_INLINE int CArray<TYPE, ARG_TYPE>::Add(ARG_TYPE newElement)
  275.     { int nIndex = m_nSize;
  276.         SetAtGrow(nIndex, newElement);
  277.         return nIndex; }
  278. template<class TYPE, class ARG_TYPE>
  279. AFX_INLINE TYPE CArray<TYPE, ARG_TYPE>::operator[](int nIndex) const
  280.     { return GetAt(nIndex); }
  281. template<class TYPE, class ARG_TYPE>
  282. AFX_INLINE TYPE& CArray<TYPE, ARG_TYPE>::operator[](int nIndex)
  283.     { return ElementAt(nIndex); }
  284.  
  285. /////////////////////////////////////////////////////////////////////////////
  286. // CArray<TYPE, ARG_TYPE> out-of-line functions
  287.  
  288. template<class TYPE, class ARG_TYPE>
  289. CArray<TYPE, ARG_TYPE>::CArray()
  290. {
  291.     m_pData = NULL;
  292.     m_nSize = m_nMaxSize = m_nGrowBy = 0;
  293. }
  294.  
  295. template<class TYPE, class ARG_TYPE>
  296. CArray<TYPE, ARG_TYPE>::~CArray()
  297. {
  298.     ASSERT_VALID(this);
  299.  
  300.     if (m_pData != NULL)
  301.     {
  302.         DestructElements<TYPE>(m_pData, m_nSize);
  303.         delete[] (BYTE*)m_pData;
  304.     }
  305. }
  306.  
  307. template<class TYPE, class ARG_TYPE>
  308. void CArray<TYPE, ARG_TYPE>::SetSize(int nNewSize, int nGrowBy)
  309. {
  310.     ASSERT_VALID(this);
  311.     ASSERT(nNewSize >= 0);
  312.  
  313.     if (nGrowBy != -1)
  314.         m_nGrowBy = nGrowBy;  // set new size
  315.  
  316.     if (nNewSize == 0)
  317.     {
  318.         // shrink to nothing
  319.         if (m_pData != NULL)
  320.         {
  321.             DestructElements<TYPE>(m_pData, m_nSize);
  322.             delete[] (BYTE*)m_pData;
  323.             m_pData = NULL;
  324.         }
  325.         m_nSize = m_nMaxSize = 0;
  326.     }
  327.     else if (m_pData == NULL)
  328.     {
  329.         // create one with exact size
  330. #ifdef SIZE_T_MAX
  331.         ASSERT(nNewSize <= SIZE_T_MAX/sizeof(TYPE));    // no overflow
  332. #endif
  333.         m_pData = (TYPE*) new BYTE[nNewSize * sizeof(TYPE)];
  334.         ConstructElements<TYPE>(m_pData, nNewSize);
  335.         m_nSize = m_nMaxSize = nNewSize;
  336.     }
  337.     else if (nNewSize <= m_nMaxSize)
  338.     {
  339.         // it fits
  340.         if (nNewSize > m_nSize)
  341.         {
  342.             // initialize the new elements
  343.             ConstructElements<TYPE>(&m_pData[m_nSize], nNewSize-m_nSize);
  344.         }
  345.         else if (m_nSize > nNewSize)
  346.         {
  347.             // destroy the old elements
  348.             DestructElements<TYPE>(&m_pData[nNewSize], m_nSize-nNewSize);
  349.         }
  350.         m_nSize = nNewSize;
  351.     }
  352.     else
  353.     {
  354.         // otherwise, grow array
  355.         int nGrowBy = m_nGrowBy;
  356.         if (nGrowBy == 0)
  357.         {
  358.             // heuristically determine growth when nGrowBy == 0
  359.             //  (this avoids heap fragmentation in many situations)
  360.             nGrowBy = m_nSize / 8;
  361.             nGrowBy = (nGrowBy < 4) ? 4 : ((nGrowBy > 1024) ? 1024 : nGrowBy);
  362.         }
  363.         int nNewMax;
  364.         if (nNewSize < m_nMaxSize + nGrowBy)
  365.             nNewMax = m_nMaxSize + nGrowBy;  // granularity
  366.         else
  367.             nNewMax = nNewSize;  // no slush
  368.  
  369.         ASSERT(nNewMax >= m_nMaxSize);  // no wrap around
  370. #ifdef SIZE_T_MAX
  371.         ASSERT(nNewMax <= SIZE_T_MAX/sizeof(TYPE)); // no overflow
  372. #endif
  373.         TYPE* pNewData = (TYPE*) new BYTE[nNewMax * sizeof(TYPE)];
  374.  
  375.         // copy new data from old
  376.         memcpy(pNewData, m_pData, m_nSize * sizeof(TYPE));
  377.  
  378.         // construct remaining elements
  379.         ASSERT(nNewSize > m_nSize);
  380.         ConstructElements<TYPE>(&pNewData[m_nSize], nNewSize-m_nSize);
  381.  
  382.         // get rid of old stuff (note: no destructors called)
  383.         delete[] (BYTE*)m_pData;
  384.         m_pData = pNewData;
  385.         m_nSize = nNewSize;
  386.         m_nMaxSize = nNewMax;
  387.     }
  388. }
  389.  
  390. template<class TYPE, class ARG_TYPE>
  391. int CArray<TYPE, ARG_TYPE>::Append(const CArray& src)
  392. {
  393.     ASSERT_VALID(this);
  394.     ASSERT(this != &src);   // cannot append to itself
  395.  
  396.     int nOldSize = m_nSize;
  397.     SetSize(m_nSize + src.m_nSize);
  398.     CopyElements<TYPE>(m_pData + nOldSize, src.m_pData, src.m_nSize);
  399.     return nOldSize;
  400. }
  401.  
  402. template<class TYPE, class ARG_TYPE>
  403. void CArray<TYPE, ARG_TYPE>::Copy(const CArray& src)
  404. {
  405.     ASSERT_VALID(this);
  406.     ASSERT(this != &src);   // cannot append to itself
  407.  
  408.     SetSize(src.m_nSize);
  409.     CopyElements<TYPE>(m_pData, src.m_pData, src.m_nSize);
  410. }
  411.  
  412. template<class TYPE, class ARG_TYPE>
  413. void CArray<TYPE, ARG_TYPE>::FreeExtra()
  414. {
  415.     ASSERT_VALID(this);
  416.  
  417.     if (m_nSize != m_nMaxSize)
  418.     {
  419.         // shrink to desired size
  420. #ifdef SIZE_T_MAX
  421.         ASSERT(m_nSize <= SIZE_T_MAX/sizeof(TYPE)); // no overflow
  422. #endif
  423.         TYPE* pNewData = NULL;
  424.         if (m_nSize != 0)
  425.         {
  426.             pNewData = (TYPE*) new BYTE[m_nSize * sizeof(TYPE)];
  427.             // copy new data from old
  428.             memcpy(pNewData, m_pData, m_nSize * sizeof(TYPE));
  429.         }
  430.  
  431.         // get rid of old stuff (note: no destructors called)
  432.         delete[] (BYTE*)m_pData;
  433.         m_pData = pNewData;
  434.         m_nMaxSize = m_nSize;
  435.     }
  436. }
  437.  
  438. template<class TYPE, class ARG_TYPE>
  439. void CArray<TYPE, ARG_TYPE>::SetAtGrow(int nIndex, ARG_TYPE newElement)
  440. {
  441.     ASSERT_VALID(this);
  442.     ASSERT(nIndex >= 0);
  443.  
  444.     if (nIndex >= m_nSize)
  445.         SetSize(nIndex+1, -1);
  446.     m_pData[nIndex] = newElement;
  447. }
  448.  
  449. template<class TYPE, class ARG_TYPE>
  450. void CArray<TYPE, ARG_TYPE>::InsertAt(int nIndex, ARG_TYPE newElement, int nCount /*=1*/)
  451. {
  452.     ASSERT_VALID(this);
  453.     ASSERT(nIndex >= 0);    // will expand to meet need
  454.     ASSERT(nCount > 0);     // zero or negative size not allowed
  455.  
  456.     if (nIndex >= m_nSize)
  457.     {
  458.         // adding after the end of the array
  459.         SetSize(nIndex + nCount, -1);   // grow so nIndex is valid
  460.     }
  461.     else
  462.     {
  463.         // inserting in the middle of the array
  464.         int nOldSize = m_nSize;
  465.         SetSize(m_nSize + nCount, -1);  // grow it to new size
  466.         // destroy intial data before copying over it
  467.         DestructElements<TYPE>(&m_pData[nOldSize], nCount);
  468.         // shift old data up to fill gap
  469.         memmove(&m_pData[nIndex+nCount], &m_pData[nIndex],
  470.             (nOldSize-nIndex) * sizeof(TYPE));
  471.  
  472.         // re-init slots we copied from
  473.         ConstructElements<TYPE>(&m_pData[nIndex], nCount);
  474.     }
  475.  
  476.     // insert new value in the gap
  477.     ASSERT(nIndex + nCount <= m_nSize);
  478.     while (nCount--)
  479.         m_pData[nIndex++] = newElement;
  480. }
  481.  
  482. template<class TYPE, class ARG_TYPE>
  483. void CArray<TYPE, ARG_TYPE>::RemoveAt(int nIndex, int nCount)
  484. {
  485.     ASSERT_VALID(this);
  486.     ASSERT(nIndex >= 0);
  487.     ASSERT(nCount >= 0);
  488.     ASSERT(nIndex + nCount <= m_nSize);
  489.  
  490.     // just remove a range
  491.     int nMoveCount = m_nSize - (nIndex + nCount);
  492.     DestructElements<TYPE>(&m_pData[nIndex], nCount);
  493.     if (nMoveCount)
  494.         memmove(&m_pData[nIndex], &m_pData[nIndex + nCount],
  495.             nMoveCount * sizeof(TYPE));
  496.     m_nSize -= nCount;
  497. }
  498.  
  499. template<class TYPE, class ARG_TYPE>
  500. void CArray<TYPE, ARG_TYPE>::InsertAt(int nStartIndex, CArray* pNewArray)
  501. {
  502.     ASSERT_VALID(this);
  503.     ASSERT(pNewArray != NULL);
  504.     ASSERT_VALID(pNewArray);
  505.     ASSERT(nStartIndex >= 0);
  506.  
  507.     if (pNewArray->GetSize() > 0)
  508.     {
  509.         InsertAt(nStartIndex, pNewArray->GetAt(0), pNewArray->GetSize());
  510.         for (int i = 0; i < pNewArray->GetSize(); i++)
  511.             SetAt(nStartIndex + i, pNewArray->GetAt(i));
  512.     }
  513. }
  514.  
  515. template<class TYPE, class ARG_TYPE>
  516. void CArray<TYPE, ARG_TYPE>::Serialize(CArchive& ar)
  517. {
  518.     ASSERT_VALID(this);
  519.  
  520.     CObject::Serialize(ar);
  521.     if (ar.IsStoring())
  522.     {
  523.         ar.WriteCount(m_nSize);
  524.     }
  525.     else
  526.     {
  527.         DWORD nOldSize = ar.ReadCount();
  528.         SetSize(nOldSize, -1);
  529.     }
  530.     SerializeElements<TYPE>(ar, m_pData, m_nSize);
  531. }
  532.  
  533. #ifdef _DEBUG
  534. template<class TYPE, class ARG_TYPE>
  535. void CArray<TYPE, ARG_TYPE>::Dump(CDumpContext& dc) const
  536. {
  537.     CObject::Dump(dc);
  538.  
  539.     dc << "with " << m_nSize << " elements";
  540.     if (dc.GetDepth() > 0)
  541.     {
  542.         dc << "\n";
  543.         DumpElements<TYPE>(dc, m_pData, m_nSize);
  544.     }
  545.  
  546.     dc << "\n";
  547. }
  548.  
  549. template<class TYPE, class ARG_TYPE>
  550. void CArray<TYPE, ARG_TYPE>::AssertValid() const
  551. {
  552.     CObject::AssertValid();
  553.  
  554.     if (m_pData == NULL)
  555.     {
  556.         ASSERT(m_nSize == 0);
  557.         ASSERT(m_nMaxSize == 0);
  558.     }
  559.     else
  560.     {
  561.         ASSERT(m_nSize >= 0);
  562.         ASSERT(m_nMaxSize >= 0);
  563.         ASSERT(m_nSize <= m_nMaxSize);
  564.         ASSERT(AfxIsValidAddress(m_pData, m_nMaxSize * sizeof(TYPE)));
  565.     }
  566. }
  567. #endif //_DEBUG
  568.  
  569. /////////////////////////////////////////////////////////////////////////////
  570. // CList<TYPE, ARG_TYPE>
  571.  
  572. template<class TYPE, class ARG_TYPE>
  573. class CList : public CObject
  574. {
  575. protected:
  576.     struct CNode
  577.     {
  578.         CNode* pNext;
  579.         CNode* pPrev;
  580.         TYPE data;
  581.     };
  582. public:
  583. // Construction
  584.     CList(int nBlockSize = 10);
  585.  
  586. // Attributes (head and tail)
  587.     // count of elements
  588.     int GetCount() const;
  589.     BOOL IsEmpty() const;
  590.  
  591.     // peek at head or tail
  592.     TYPE& GetHead();
  593.     TYPE GetHead() const;
  594.     TYPE& GetTail();
  595.     TYPE GetTail() const;
  596.  
  597. // Operations
  598.     // get head or tail (and remove it) - don't call on empty list !
  599.     TYPE RemoveHead();
  600.     TYPE RemoveTail();
  601.  
  602.     // add before head or after tail
  603.     POSITION AddHead(ARG_TYPE newElement);
  604.     POSITION AddTail(ARG_TYPE newElement);
  605.  
  606.     // add another list of elements before head or after tail
  607.     void AddHead(CList* pNewList);
  608.     void AddTail(CList* pNewList);
  609.  
  610.     // remove all elements
  611.     void RemoveAll();
  612.  
  613.     // iteration
  614.     POSITION GetHeadPosition() const;
  615.     POSITION GetTailPosition() const;
  616.     TYPE& GetNext(POSITION& rPosition); // return *Position++
  617.     TYPE GetNext(POSITION& rPosition) const; // return *Position++
  618.     TYPE& GetPrev(POSITION& rPosition); // return *Position--
  619.     TYPE GetPrev(POSITION& rPosition) const; // return *Position--
  620.  
  621.     // getting/modifying an element at a given position
  622.     TYPE& GetAt(POSITION position);
  623.     TYPE GetAt(POSITION position) const;
  624.     void SetAt(POSITION pos, ARG_TYPE newElement);
  625.     void RemoveAt(POSITION position);
  626.  
  627.     // inserting before or after a given position
  628.     POSITION InsertBefore(POSITION position, ARG_TYPE newElement);
  629.     POSITION InsertAfter(POSITION position, ARG_TYPE newElement);
  630.  
  631.     // helper functions (note: O(n) speed)
  632.     POSITION Find(ARG_TYPE searchValue, POSITION startAfter = NULL) const;
  633.         // defaults to starting at the HEAD, return NULL if not found
  634.     POSITION FindIndex(int nIndex) const;
  635.         // get the 'nIndex'th element (may return NULL)
  636.  
  637. // Implementation
  638. protected:
  639.     CNode* m_pNodeHead;
  640.     CNode* m_pNodeTail;
  641.     int m_nCount;
  642.     CNode* m_pNodeFree;
  643.     struct CPlex* m_pBlocks;
  644.     int m_nBlockSize;
  645.  
  646.     CNode* NewNode(CNode*, CNode*);
  647.     void FreeNode(CNode*);
  648.  
  649. public:
  650.     ~CList();
  651.     void Serialize(CArchive&);
  652. #ifdef _DEBUG
  653.     void Dump(CDumpContext&) const;
  654.     void AssertValid() const;
  655. #endif
  656. };
  657.  
  658. /////////////////////////////////////////////////////////////////////////////
  659. // CList<TYPE, ARG_TYPE> inline functions
  660.  
  661. template<class TYPE, class ARG_TYPE>
  662. AFX_INLINE int CList<TYPE, ARG_TYPE>::GetCount() const
  663.     { return m_nCount; }
  664. template<class TYPE, class ARG_TYPE>
  665. AFX_INLINE BOOL CList<TYPE, ARG_TYPE>::IsEmpty() const
  666.     { return m_nCount == 0; }
  667. template<class TYPE, class ARG_TYPE>
  668. AFX_INLINE TYPE& CList<TYPE, ARG_TYPE>::GetHead()
  669.     { ASSERT(m_pNodeHead != NULL);
  670.         return m_pNodeHead->data; }
  671. template<class TYPE, class ARG_TYPE>
  672. AFX_INLINE TYPE CList<TYPE, ARG_TYPE>::GetHead() const
  673.     { ASSERT(m_pNodeHead != NULL);
  674.         return m_pNodeHead->data; }
  675. template<class TYPE, class ARG_TYPE>
  676. AFX_INLINE TYPE& CList<TYPE, ARG_TYPE>::GetTail()
  677.     { ASSERT(m_pNodeTail != NULL);
  678.         return m_pNodeTail->data; }
  679. template<class TYPE, class ARG_TYPE>
  680. AFX_INLINE TYPE CList<TYPE, ARG_TYPE>::GetTail() const
  681.     { ASSERT(m_pNodeTail != NULL);
  682.         return m_pNodeTail->data; }
  683. template<class TYPE, class ARG_TYPE>
  684. AFX_INLINE POSITION CList<TYPE, ARG_TYPE>::GetHeadPosition() const
  685.     { return (POSITION) m_pNodeHead; }
  686. template<class TYPE, class ARG_TYPE>
  687. AFX_INLINE POSITION CList<TYPE, ARG_TYPE>::GetTailPosition() const
  688.     { return (POSITION) m_pNodeTail; }
  689. template<class TYPE, class ARG_TYPE>
  690. AFX_INLINE TYPE& CList<TYPE, ARG_TYPE>::GetNext(POSITION& rPosition) // return *Position++
  691.     { CNode* pNode = (CNode*) rPosition;
  692.         ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  693.         rPosition = (POSITION) pNode->pNext;
  694.         return pNode->data; }
  695. template<class TYPE, class ARG_TYPE>
  696. AFX_INLINE TYPE CList<TYPE, ARG_TYPE>::GetNext(POSITION& rPosition) const // return *Position++
  697.     { CNode* pNode = (CNode*) rPosition;
  698.         ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  699.         rPosition = (POSITION) pNode->pNext;
  700.         return pNode->data; }
  701. template<class TYPE, class ARG_TYPE>
  702. AFX_INLINE TYPE& CList<TYPE, ARG_TYPE>::GetPrev(POSITION& rPosition) // return *Position--
  703.     { CNode* pNode = (CNode*) rPosition;
  704.         ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  705.         rPosition = (POSITION) pNode->pPrev;
  706.         return pNode->data; }
  707. template<class TYPE, class ARG_TYPE>
  708. AFX_INLINE TYPE CList<TYPE, ARG_TYPE>::GetPrev(POSITION& rPosition) const // return *Position--
  709.     { CNode* pNode = (CNode*) rPosition;
  710.         ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  711.         rPosition = (POSITION) pNode->pPrev;
  712.         return pNode->data; }
  713. template<class TYPE, class ARG_TYPE>
  714. AFX_INLINE TYPE& CList<TYPE, ARG_TYPE>::GetAt(POSITION position)
  715.     { CNode* pNode = (CNode*) position;
  716.         ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  717.         return pNode->data; }
  718. template<class TYPE, class ARG_TYPE>
  719. AFX_INLINE TYPE CList<TYPE, ARG_TYPE>::GetAt(POSITION position) const
  720.     { CNode* pNode = (CNode*) position;
  721.         ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  722.         return pNode->data; }
  723. template<class TYPE, class ARG_TYPE>
  724. AFX_INLINE void CList<TYPE, ARG_TYPE>::SetAt(POSITION pos, ARG_TYPE newElement)
  725.     { CNode* pNode = (CNode*) pos;
  726.         ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  727.         pNode->data = newElement; }
  728.  
  729. template<class TYPE, class ARG_TYPE>
  730. CList<TYPE, ARG_TYPE>::CList(int nBlockSize)
  731. {
  732.     ASSERT(nBlockSize > 0);
  733.  
  734.     m_nCount = 0;
  735.     m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL;
  736.     m_pBlocks = NULL;
  737.     m_nBlockSize = nBlockSize;
  738. }
  739.  
  740. template<class TYPE, class ARG_TYPE>
  741. void CList<TYPE, ARG_TYPE>::RemoveAll()
  742. {
  743.     ASSERT_VALID(this);
  744.  
  745.     // destroy elements
  746.     CNode* pNode;
  747.     for (pNode = m_pNodeHead; pNode != NULL; pNode = pNode->pNext)
  748.         DestructElements<TYPE>(&pNode->data, 1);
  749.  
  750.     m_nCount = 0;
  751.     m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL;
  752.     m_pBlocks->FreeDataChain();
  753.     m_pBlocks = NULL;
  754. }
  755.  
  756. template<class TYPE, class ARG_TYPE>
  757. CList<TYPE, ARG_TYPE>::~CList()
  758. {
  759.     RemoveAll();
  760.     ASSERT(m_nCount == 0);
  761. }
  762.  
  763. /////////////////////////////////////////////////////////////////////////////
  764. // Node helpers
  765. //
  766. // Implementation note: CNode's are stored in CPlex blocks and
  767. //  chained together. Free blocks are maintained in a singly linked list
  768. //  using the 'pNext' member of CNode with 'm_pNodeFree' as the head.
  769. //  Used blocks are maintained in a doubly linked list using both 'pNext'
  770. //  and 'pPrev' as links and 'm_pNodeHead' and 'm_pNodeTail'
  771. //   as the head/tail.
  772. //
  773. // We never free a CPlex block unless the List is destroyed or RemoveAll()
  774. //  is used - so the total number of CPlex blocks may grow large depending
  775. //  on the maximum past size of the list.
  776. //
  777.  
  778. template<class TYPE, class ARG_TYPE>
  779. CList<TYPE, ARG_TYPE>::CNode*
  780. CList<TYPE, ARG_TYPE>::NewNode(CList::CNode* pPrev, CList::CNode* pNext)
  781. {
  782.     if (m_pNodeFree == NULL)
  783.     {
  784.         // add another block
  785.         CPlex* pNewBlock = CPlex::Create(m_pBlocks, m_nBlockSize,
  786.                  sizeof(CNode));
  787.  
  788.         // chain them into free list
  789.         CNode* pNode = (CNode*) pNewBlock->data();
  790.         // free in reverse order to make it easier to debug
  791.         pNode += m_nBlockSize - 1;
  792.         for (int i = m_nBlockSize-1; i >= 0; i--, pNode--)
  793.         {
  794.             pNode->pNext = m_pNodeFree;
  795.             m_pNodeFree = pNode;
  796.         }
  797.     }
  798.     ASSERT(m_pNodeFree != NULL);  // we must have something
  799.  
  800.     CList::CNode* pNode = m_pNodeFree;
  801.     m_pNodeFree = m_pNodeFree->pNext;
  802.     pNode->pPrev = pPrev;
  803.     pNode->pNext = pNext;
  804.     m_nCount++;
  805.     ASSERT(m_nCount > 0);  // make sure we don't overflow
  806.  
  807.     ConstructElements<TYPE>(&pNode->data, 1);
  808.     return pNode;
  809. }
  810.  
  811. template<class TYPE, class ARG_TYPE>
  812. void CList<TYPE, ARG_TYPE>::FreeNode(CList::CNode* pNode)
  813. {
  814.     DestructElements<TYPE>(&pNode->data, 1);
  815.     pNode->pNext = m_pNodeFree;
  816.     m_pNodeFree = pNode;
  817.     m_nCount--;
  818.     ASSERT(m_nCount >= 0);  // make sure we don't underflow
  819.  
  820.     // if no more elements, cleanup completely
  821.     if (m_nCount == 0)
  822.         RemoveAll();
  823. }
  824.  
  825. template<class TYPE, class ARG_TYPE>
  826. POSITION CList<TYPE, ARG_TYPE>::AddHead(ARG_TYPE newElement)
  827. {
  828.     ASSERT_VALID(this);
  829.  
  830.     CNode* pNewNode = NewNode(NULL, m_pNodeHead);
  831.     pNewNode->data = newElement;
  832.     if (m_pNodeHead != NULL)
  833.         m_pNodeHead->pPrev = pNewNode;
  834.     else
  835.         m_pNodeTail = pNewNode;
  836.     m_pNodeHead = pNewNode;
  837.     return (POSITION) pNewNode;
  838. }
  839.  
  840. template<class TYPE, class ARG_TYPE>
  841. POSITION CList<TYPE, ARG_TYPE>::AddTail(ARG_TYPE newElement)
  842. {
  843.     ASSERT_VALID(this);
  844.  
  845.     CNode* pNewNode = NewNode(m_pNodeTail, NULL);
  846.     pNewNode->data = newElement;
  847.     if (m_pNodeTail != NULL)
  848.         m_pNodeTail->pNext = pNewNode;
  849.     else
  850.         m_pNodeHead = pNewNode;
  851.     m_pNodeTail = pNewNode;
  852.     return (POSITION) pNewNode;
  853. }
  854.  
  855. template<class TYPE, class ARG_TYPE>
  856. void CList<TYPE, ARG_TYPE>::AddHead(CList* pNewList)
  857. {
  858.     ASSERT_VALID(this);
  859.  
  860.     ASSERT(pNewList != NULL);
  861.     ASSERT_VALID(pNewList);
  862.  
  863.     // add a list of same elements to head (maintain order)
  864.     POSITION pos = pNewList->GetTailPosition();
  865.     while (pos != NULL)
  866.         AddHead(pNewList->GetPrev(pos));
  867. }
  868.  
  869. template<class TYPE, class ARG_TYPE>
  870. void CList<TYPE, ARG_TYPE>::AddTail(CList* pNewList)
  871. {
  872.     ASSERT_VALID(this);
  873.     ASSERT(pNewList != NULL);
  874.     ASSERT_VALID(pNewList);
  875.  
  876.     // add a list of same elements
  877.     POSITION pos = pNewList->GetHeadPosition();
  878.     while (pos != NULL)
  879.         AddTail(pNewList->GetNext(pos));
  880. }
  881.  
  882. template<class TYPE, class ARG_TYPE>
  883. TYPE CList<TYPE, ARG_TYPE>::RemoveHead()
  884. {
  885.     ASSERT_VALID(this);
  886.     ASSERT(m_pNodeHead != NULL);  // don't call on empty list !!!
  887.     ASSERT(AfxIsValidAddress(m_pNodeHead, sizeof(CNode)));
  888.  
  889.     CNode* pOldNode = m_pNodeHead;
  890.     TYPE returnValue = pOldNode->data;
  891.  
  892.     m_pNodeHead = pOldNode->pNext;
  893.     if (m_pNodeHead != NULL)
  894.         m_pNodeHead->pPrev = NULL;
  895.     else
  896.         m_pNodeTail = NULL;
  897.     FreeNode(pOldNode);
  898.     return returnValue;
  899. }
  900.  
  901. template<class TYPE, class ARG_TYPE>
  902. TYPE CList<TYPE, ARG_TYPE>::RemoveTail()
  903. {
  904.     ASSERT_VALID(this);
  905.     ASSERT(m_pNodeTail != NULL);  // don't call on empty list !!!
  906.     ASSERT(AfxIsValidAddress(m_pNodeTail, sizeof(CNode)));
  907.  
  908.     CNode* pOldNode = m_pNodeTail;
  909.     TYPE returnValue = pOldNode->data;
  910.  
  911.     m_pNodeTail = pOldNode->pPrev;
  912.     if (m_pNodeTail != NULL)
  913.         m_pNodeTail->pNext = NULL;
  914.     else
  915.         m_pNodeHead = NULL;
  916.     FreeNode(pOldNode);
  917.     return returnValue;
  918. }
  919.  
  920. template<class TYPE, class ARG_TYPE>
  921. POSITION CList<TYPE, ARG_TYPE>::InsertBefore(POSITION position, ARG_TYPE newElement)
  922. {
  923.     ASSERT_VALID(this);
  924.  
  925.     if (position == NULL)
  926.         return AddHead(newElement); // insert before nothing -> head of the list
  927.  
  928.     // Insert it before position
  929.     CNode* pOldNode = (CNode*) position;
  930.     CNode* pNewNode = NewNode(pOldNode->pPrev, pOldNode);
  931.     pNewNode->data = newElement;
  932.  
  933.     if (pOldNode->pPrev != NULL)
  934.     {
  935.         ASSERT(AfxIsValidAddress(pOldNode->pPrev, sizeof(CNode)));
  936.         pOldNode->pPrev->pNext = pNewNode;
  937.     }
  938.     else
  939.     {
  940.         ASSERT(pOldNode == m_pNodeHead);
  941.         m_pNodeHead = pNewNode;
  942.     }
  943.     pOldNode->pPrev = pNewNode;
  944.     return (POSITION) pNewNode;
  945. }
  946.  
  947. template<class TYPE, class ARG_TYPE>
  948. POSITION CList<TYPE, ARG_TYPE>::InsertAfter(POSITION position, ARG_TYPE newElement)
  949. {
  950.     ASSERT_VALID(this);
  951.  
  952.     if (position == NULL)
  953.         return AddTail(newElement); // insert after nothing -> tail of the list
  954.  
  955.     // Insert it before position
  956.     CNode* pOldNode = (CNode*) position;
  957.     ASSERT(AfxIsValidAddress(pOldNode, sizeof(CNode)));
  958.     CNode* pNewNode = NewNode(pOldNode, pOldNode->pNext);
  959.     pNewNode->data = newElement;
  960.  
  961.     if (pOldNode->pNext != NULL)
  962.     {
  963.         ASSERT(AfxIsValidAddress(pOldNode->pNext, sizeof(CNode)));
  964.         pOldNode->pNext->pPrev = pNewNode;
  965.     }
  966.     else
  967.     {
  968.         ASSERT(pOldNode == m_pNodeTail);
  969.         m_pNodeTail = pNewNode;
  970.     }
  971.     pOldNode->pNext = pNewNode;
  972.     return (POSITION) pNewNode;
  973. }
  974.  
  975. template<class TYPE, class ARG_TYPE>
  976. void CList<TYPE, ARG_TYPE>::RemoveAt(POSITION position)
  977. {
  978.     ASSERT_VALID(this);
  979.  
  980.     CNode* pOldNode = (CNode*) position;
  981.     ASSERT(AfxIsValidAddress(pOldNode, sizeof(CNode)));
  982.  
  983.     // remove pOldNode from list
  984.     if (pOldNode == m_pNodeHead)
  985.     {
  986.         m_pNodeHead = pOldNode->pNext;
  987.     }
  988.     else
  989.     {
  990.         ASSERT(AfxIsValidAddress(pOldNode->pPrev, sizeof(CNode)));
  991.         pOldNode->pPrev->pNext = pOldNode->pNext;
  992.     }
  993.     if (pOldNode == m_pNodeTail)
  994.     {
  995.         m_pNodeTail = pOldNode->pPrev;
  996.     }
  997.     else
  998.     {
  999.         ASSERT(AfxIsValidAddress(pOldNode->pNext, sizeof(CNode)));
  1000.         pOldNode->pNext->pPrev = pOldNode->pPrev;
  1001.     }
  1002.     FreeNode(pOldNode);
  1003. }
  1004.  
  1005. template<class TYPE, class ARG_TYPE>
  1006. POSITION CList<TYPE, ARG_TYPE>::FindIndex(int nIndex) const
  1007. {
  1008.     ASSERT_VALID(this);
  1009.  
  1010.     if (nIndex >= m_nCount || nIndex < 0)
  1011.         return NULL;  // went too far
  1012.  
  1013.     CNode* pNode = m_pNodeHead;
  1014.     while (nIndex--)
  1015.     {
  1016.         ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  1017.         pNode = pNode->pNext;
  1018.     }
  1019.     return (POSITION) pNode;
  1020. }
  1021.  
  1022. template<class TYPE, class ARG_TYPE>
  1023. POSITION CList<TYPE, ARG_TYPE>::Find(ARG_TYPE searchValue, POSITION startAfter) const
  1024. {
  1025.     ASSERT_VALID(this);
  1026.  
  1027.     CNode* pNode = (CNode*) startAfter;
  1028.     if (pNode == NULL)
  1029.     {
  1030.         pNode = m_pNodeHead;  // start at head
  1031.     }
  1032.     else
  1033.     {
  1034.         ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  1035.         pNode = pNode->pNext;  // start after the one specified
  1036.     }
  1037.  
  1038.     for (; pNode != NULL; pNode = pNode->pNext)
  1039.         if (CompareElements<TYPE>(&pNode->data, &searchValue))
  1040.             return (POSITION)pNode;
  1041.     return NULL;
  1042. }
  1043.  
  1044. template<class TYPE, class ARG_TYPE>
  1045. void CList<TYPE, ARG_TYPE>::Serialize(CArchive& ar)
  1046. {
  1047.     ASSERT_VALID(this);
  1048.  
  1049.     CObject::Serialize(ar);
  1050.  
  1051.     if (ar.IsStoring())
  1052.     {
  1053.         ar.WriteCount(m_nCount);
  1054.         for (CNode* pNode = m_pNodeHead; pNode != NULL; pNode = pNode->pNext)
  1055.         {
  1056.             ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  1057.             SerializeElements<TYPE>(ar, &pNode->data, 1);
  1058.         }
  1059.     }
  1060.     else
  1061.     {
  1062.         DWORD nNewCount = ar.ReadCount();
  1063.         while (nNewCount--)
  1064.         {
  1065.             TYPE newData;
  1066.             SerializeElements<TYPE>(ar, &newData, 1);
  1067.             AddTail(newData);
  1068.         }
  1069.     }
  1070. }
  1071.  
  1072. #ifdef _DEBUG
  1073. template<class TYPE, class ARG_TYPE>
  1074. void CList<TYPE, ARG_TYPE>::Dump(CDumpContext& dc) const
  1075. {
  1076.     CObject::Dump(dc);
  1077.  
  1078.     dc << "with " << m_nCount << " elements";
  1079.     if (dc.GetDepth() > 0)
  1080.     {
  1081.         POSITION pos = GetHeadPosition();
  1082.         while (pos != NULL)
  1083.         {
  1084.             dc << "\n";
  1085.             DumpElements<TYPE>(dc, &((CList*)this)->GetNext(pos), 1);
  1086.         }
  1087.     }
  1088.  
  1089.     dc << "\n";
  1090. }
  1091.  
  1092. template<class TYPE, class ARG_TYPE>
  1093. void CList<TYPE, ARG_TYPE>::AssertValid() const
  1094. {
  1095.     CObject::AssertValid();
  1096.  
  1097.     if (m_nCount == 0)
  1098.     {
  1099.         // empty list
  1100.         ASSERT(m_pNodeHead == NULL);
  1101.         ASSERT(m_pNodeTail == NULL);
  1102.     }
  1103.     else
  1104.     {
  1105.         // non-empty list
  1106.         ASSERT(AfxIsValidAddress(m_pNodeHead, sizeof(CNode)));
  1107.         ASSERT(AfxIsValidAddress(m_pNodeTail, sizeof(CNode)));
  1108.     }
  1109. }
  1110. #endif //_DEBUG
  1111.  
  1112. /////////////////////////////////////////////////////////////////////////////
  1113. // CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>
  1114.  
  1115. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1116. class CMap : public CObject
  1117. {
  1118. protected:
  1119.     // Association
  1120.     struct CAssoc
  1121.     {
  1122.         CAssoc* pNext;
  1123.         UINT nHashValue;  // needed for efficient iteration
  1124.         KEY key;
  1125.         VALUE value;
  1126.     };
  1127. public:
  1128. // Construction
  1129.     CMap(int nBlockSize = 10);
  1130.  
  1131. // Attributes
  1132.     // number of elements
  1133.     int GetCount() const;
  1134.     BOOL IsEmpty() const;
  1135.  
  1136.     // Lookup
  1137.     BOOL Lookup(ARG_KEY key, VALUE& rValue) const;
  1138.  
  1139. // Operations
  1140.     // Lookup and add if not there
  1141.     VALUE& operator[](ARG_KEY key);
  1142.  
  1143.     // add a new (key, value) pair
  1144.     void SetAt(ARG_KEY key, ARG_VALUE newValue);
  1145.  
  1146.     // removing existing (key, ?) pair
  1147.     BOOL RemoveKey(ARG_KEY key);
  1148.     void RemoveAll();
  1149.  
  1150.     // iterating all (key, value) pairs
  1151.     POSITION GetStartPosition() const;
  1152.     void GetNextAssoc(POSITION& rNextPosition, KEY& rKey, VALUE& rValue) const;
  1153.  
  1154.     // advanced features for derived classes
  1155.     UINT GetHashTableSize() const;
  1156.     void InitHashTable(UINT hashSize, BOOL bAllocNow = TRUE);
  1157.  
  1158. // Implementation
  1159. protected:
  1160.     CAssoc** m_pHashTable;
  1161.     UINT m_nHashTableSize;
  1162.     int m_nCount;
  1163.     CAssoc* m_pFreeList;
  1164.     struct CPlex* m_pBlocks;
  1165.     int m_nBlockSize;
  1166.  
  1167.     CAssoc* NewAssoc();
  1168.     void FreeAssoc(CAssoc*);
  1169.     CAssoc* GetAssocAt(ARG_KEY, UINT&) const;
  1170.  
  1171. public:
  1172.     ~CMap();
  1173.     void Serialize(CArchive&);
  1174. #ifdef _DEBUG
  1175.     void Dump(CDumpContext&) const;
  1176.     void AssertValid() const;
  1177. #endif
  1178. };
  1179.  
  1180. /////////////////////////////////////////////////////////////////////////////
  1181. // CMap<KEY, ARG_KEY, VALUE, ARG_VALUE> inline functions
  1182.  
  1183. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1184. AFX_INLINE int CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::GetCount() const
  1185.     { return m_nCount; }
  1186. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1187. AFX_INLINE BOOL CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::IsEmpty() const
  1188.     { return m_nCount == 0; }
  1189. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1190. AFX_INLINE void CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::SetAt(ARG_KEY key, ARG_VALUE newValue)
  1191.     { (*this)[key] = newValue; }
  1192. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1193. AFX_INLINE POSITION CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::GetStartPosition() const
  1194.     { return (m_nCount == 0) ? NULL : BEFORE_START_POSITION; }
  1195. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1196. AFX_INLINE UINT CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::GetHashTableSize() const
  1197.     { return m_nHashTableSize; }
  1198.  
  1199. /////////////////////////////////////////////////////////////////////////////
  1200. // CMap<KEY, ARG_KEY, VALUE, ARG_VALUE> out-of-line functions
  1201.  
  1202. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1203. CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::CMap(int nBlockSize)
  1204. {
  1205.     ASSERT(nBlockSize > 0);
  1206.  
  1207.     m_pHashTable = NULL;
  1208.     m_nHashTableSize = 17;  // default size
  1209.     m_nCount = 0;
  1210.     m_pFreeList = NULL;
  1211.     m_pBlocks = NULL;
  1212.     m_nBlockSize = nBlockSize;
  1213. }
  1214.  
  1215. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1216. void CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::InitHashTable(
  1217.     UINT nHashSize, BOOL bAllocNow)
  1218. //
  1219. // Used to force allocation of a hash table or to override the default
  1220. //   hash table size of (which is fairly small)
  1221. {
  1222.     ASSERT_VALID(this);
  1223.     ASSERT(m_nCount == 0);
  1224.     ASSERT(nHashSize > 0);
  1225.  
  1226.     if (m_pHashTable != NULL)
  1227.     {
  1228.         // free hash table
  1229.         delete[] m_pHashTable;
  1230.         m_pHashTable = NULL;
  1231.     }
  1232.  
  1233.     if (bAllocNow)
  1234.     {
  1235.         m_pHashTable = new CAssoc* [nHashSize];
  1236.         memset(m_pHashTable, 0, sizeof(CAssoc*) * nHashSize);
  1237.     }
  1238.     m_nHashTableSize = nHashSize;
  1239. }
  1240.  
  1241. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1242. void CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::RemoveAll()
  1243. {
  1244.     ASSERT_VALID(this);
  1245.  
  1246.     if (m_pHashTable != NULL)
  1247.     {
  1248.         // destroy elements (values and keys)
  1249.         for (UINT nHash = 0; nHash < m_nHashTableSize; nHash++)
  1250.         {
  1251.             CAssoc* pAssoc;
  1252.             for (pAssoc = m_pHashTable[nHash]; pAssoc != NULL;
  1253.               pAssoc = pAssoc->pNext)
  1254.             {
  1255.                 DestructElements<VALUE>(&pAssoc->value, 1);
  1256.                 DestructElements<KEY>(&pAssoc->key, 1);
  1257.             }
  1258.         }
  1259.     }
  1260.  
  1261.     // free hash table
  1262.     delete[] m_pHashTable;
  1263.     m_pHashTable = NULL;
  1264.  
  1265.     m_nCount = 0;
  1266.     m_pFreeList = NULL;
  1267.     m_pBlocks->FreeDataChain();
  1268.     m_pBlocks = NULL;
  1269. }
  1270.  
  1271. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1272. CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::~CMap()
  1273. {
  1274.     RemoveAll();
  1275.     ASSERT(m_nCount == 0);
  1276. }
  1277.  
  1278. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1279. CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::CAssoc*
  1280. CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::NewAssoc()
  1281. {
  1282.     if (m_pFreeList == NULL)
  1283.     {
  1284.         // add another block
  1285.         CPlex* newBlock = CPlex::Create(m_pBlocks, m_nBlockSize, sizeof(CMap::CAssoc));
  1286.         // chain them into free list
  1287.         CMap::CAssoc* pAssoc = (CMap::CAssoc*) newBlock->data();
  1288.         // free in reverse order to make it easier to debug
  1289.         pAssoc += m_nBlockSize - 1;
  1290.         for (int i = m_nBlockSize-1; i >= 0; i--, pAssoc--)
  1291.         {
  1292.             pAssoc->pNext = m_pFreeList;
  1293.             m_pFreeList = pAssoc;
  1294.         }
  1295.     }
  1296.     ASSERT(m_pFreeList != NULL);  // we must have something
  1297.  
  1298.     CMap::CAssoc* pAssoc = m_pFreeList;
  1299.     m_pFreeList = m_pFreeList->pNext;
  1300.     m_nCount++;
  1301.     ASSERT(m_nCount > 0);  // make sure we don't overflow
  1302.     ConstructElements<KEY>(&pAssoc->key, 1);
  1303.     ConstructElements<VALUE>(&pAssoc->value, 1);   // special construct values
  1304.     return pAssoc;
  1305. }
  1306.  
  1307. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1308. void CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::FreeAssoc(CMap::CAssoc* pAssoc)
  1309. {
  1310.     DestructElements<VALUE>(&pAssoc->value, 1);
  1311.     DestructElements<KEY>(&pAssoc->key, 1);
  1312.     pAssoc->pNext = m_pFreeList;
  1313.     m_pFreeList = pAssoc;
  1314.     m_nCount--;
  1315.     ASSERT(m_nCount >= 0);  // make sure we don't underflow
  1316.  
  1317.     // if no more elements, cleanup completely
  1318.     if (m_nCount == 0)
  1319.         RemoveAll();
  1320. }
  1321.  
  1322. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1323. CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::CAssoc*
  1324. CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::GetAssocAt(ARG_KEY key, UINT& nHash) const
  1325. // find association (or return NULL)
  1326. {
  1327.     nHash = HashKey<ARG_KEY>(key) % m_nHashTableSize;
  1328.  
  1329.     if (m_pHashTable == NULL)
  1330.         return NULL;
  1331.  
  1332.     // see if it exists
  1333.     CAssoc* pAssoc;
  1334.     for (pAssoc = m_pHashTable[nHash]; pAssoc != NULL; pAssoc = pAssoc->pNext)
  1335.     {
  1336.         if (CompareElements(&pAssoc->key, &key))
  1337.             return pAssoc;
  1338.     }
  1339.     return NULL;
  1340. }
  1341.  
  1342. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1343. BOOL CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::Lookup(ARG_KEY key, VALUE& rValue) const
  1344. {
  1345.     ASSERT_VALID(this);
  1346.  
  1347.     UINT nHash;
  1348.     CAssoc* pAssoc = GetAssocAt(key, nHash);
  1349.     if (pAssoc == NULL)
  1350.         return FALSE;  // not in map
  1351.  
  1352.     rValue = pAssoc->value;
  1353.     return TRUE;
  1354. }
  1355.  
  1356. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1357. VALUE& CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::operator[](ARG_KEY key)
  1358. {
  1359.     ASSERT_VALID(this);
  1360.  
  1361.     UINT nHash;
  1362.     CAssoc* pAssoc;
  1363.     if ((pAssoc = GetAssocAt(key, nHash)) == NULL)
  1364.     {
  1365.         if (m_pHashTable == NULL)
  1366.             InitHashTable(m_nHashTableSize);
  1367.  
  1368.         // it doesn't exist, add a new Association
  1369.         pAssoc = NewAssoc();
  1370.         pAssoc->nHashValue = nHash;
  1371.         pAssoc->key = key;
  1372.         // 'pAssoc->value' is a constructed object, nothing more
  1373.  
  1374.         // put into hash table
  1375.         pAssoc->pNext = m_pHashTable[nHash];
  1376.         m_pHashTable[nHash] = pAssoc;
  1377.     }
  1378.     return pAssoc->value;  // return new reference
  1379. }
  1380.  
  1381. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1382. BOOL CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::RemoveKey(ARG_KEY key)
  1383. // remove key - return TRUE if removed
  1384. {
  1385.     ASSERT_VALID(this);
  1386.  
  1387.     if (m_pHashTable == NULL)
  1388.         return FALSE;  // nothing in the table
  1389.  
  1390.     CAssoc** ppAssocPrev;
  1391.     ppAssocPrev = &m_pHashTable[HashKey<ARG_KEY>(key) % m_nHashTableSize];
  1392.  
  1393.     CAssoc* pAssoc;
  1394.     for (pAssoc = *ppAssocPrev; pAssoc != NULL; pAssoc = pAssoc->pNext)
  1395.     {
  1396.         if (CompareElements(&pAssoc->key, &key))
  1397.         {
  1398.             // remove it
  1399.             *ppAssocPrev = pAssoc->pNext;  // remove from list
  1400.             FreeAssoc(pAssoc);
  1401.             return TRUE;
  1402.         }
  1403.         ppAssocPrev = &pAssoc->pNext;
  1404.     }
  1405.     return FALSE;  // not found
  1406. }
  1407.  
  1408. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1409. void CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::GetNextAssoc(POSITION& rNextPosition,
  1410.     KEY& rKey, VALUE& rValue) const
  1411. {
  1412.     ASSERT_VALID(this);
  1413.     ASSERT(m_pHashTable != NULL);  // never call on empty map
  1414.  
  1415.     CAssoc* pAssocRet = (CAssoc*)rNextPosition;
  1416.     ASSERT(pAssocRet != NULL);
  1417.  
  1418.     if (pAssocRet == (CAssoc*) BEFORE_START_POSITION)
  1419.     {
  1420.         // find the first association
  1421.         for (UINT nBucket = 0; nBucket < m_nHashTableSize; nBucket++)
  1422.             if ((pAssocRet = m_pHashTable[nBucket]) != NULL)
  1423.                 break;
  1424.         ASSERT(pAssocRet != NULL);  // must find something
  1425.     }
  1426.  
  1427.     // find next association
  1428.     ASSERT(AfxIsValidAddress(pAssocRet, sizeof(CAssoc)));
  1429.     CAssoc* pAssocNext;
  1430.     if ((pAssocNext = pAssocRet->pNext) == NULL)
  1431.     {
  1432.         // go to next bucket
  1433.         for (UINT nBucket = pAssocRet->nHashValue + 1;
  1434.           nBucket < m_nHashTableSize; nBucket++)
  1435.             if ((pAssocNext = m_pHashTable[nBucket]) != NULL)
  1436.                 break;
  1437.     }
  1438.  
  1439.     rNextPosition = (POSITION) pAssocNext;
  1440.  
  1441.     // fill in return data
  1442.     rKey = pAssocRet->key;
  1443.     rValue = pAssocRet->value;
  1444. }
  1445.  
  1446. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1447. void CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::Serialize(CArchive& ar)
  1448. {
  1449.     ASSERT_VALID(this);
  1450.  
  1451.     CObject::Serialize(ar);
  1452.  
  1453.     if (ar.IsStoring())
  1454.     {
  1455.         ar.WriteCount(m_nCount);
  1456.         if (m_nCount == 0)
  1457.             return;  // nothing more to do
  1458.  
  1459.         ASSERT(m_pHashTable != NULL);
  1460.         for (UINT nHash = 0; nHash < m_nHashTableSize; nHash++)
  1461.         {
  1462.             CAssoc* pAssoc;
  1463.             for (pAssoc = m_pHashTable[nHash]; pAssoc != NULL;
  1464.               pAssoc = pAssoc->pNext)
  1465.             {
  1466.                 SerializeElements<KEY>(ar, &pAssoc->key, 1);
  1467.                 SerializeElements<VALUE>(ar, &pAssoc->value, 1);
  1468.             }
  1469.         }
  1470.     }
  1471.     else
  1472.     {
  1473.         DWORD nNewCount = ar.ReadCount();
  1474.         while (nNewCount--)
  1475.         {
  1476.             KEY newKey;
  1477.             VALUE newValue;
  1478.             SerializeElements<KEY>(ar, &newKey, 1);
  1479.             SerializeElements<VALUE>(ar, &newValue, 1);
  1480.             SetAt(newKey, newValue);
  1481.         }
  1482.     }
  1483. }
  1484.  
  1485. #ifdef _DEBUG
  1486. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1487. void CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::Dump(CDumpContext& dc) const
  1488. {
  1489.     CObject::Dump(dc);
  1490.  
  1491.     dc << "with " << m_nCount << " elements";
  1492.     if (dc.GetDepth() > 0)
  1493.     {
  1494.         // Dump in format "[key] -> value"
  1495.         KEY key;
  1496.         VALUE val;
  1497.  
  1498.         POSITION pos = GetStartPosition();
  1499.         while (pos != NULL)
  1500.         {
  1501.             GetNextAssoc(pos, key, val);
  1502.             dc << "\n\t[";
  1503.             DumpElements<KEY>(dc, &key, 1);
  1504.             dc << "] = ";
  1505.             DumpElements<VALUE>(dc, &val, 1);
  1506.         }
  1507.     }
  1508.  
  1509.     dc << "\n";
  1510. }
  1511.  
  1512. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1513. void CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::AssertValid() const
  1514. {
  1515.     CObject::AssertValid();
  1516.  
  1517.     ASSERT(m_nHashTableSize > 0);
  1518.     ASSERT(m_nCount == 0 || m_pHashTable != NULL);
  1519.         // non-empty map should have hash table
  1520. }
  1521. #endif //_DEBUG
  1522.  
  1523. /////////////////////////////////////////////////////////////////////////////
  1524. // CTypedPtrArray<BASE_CLASS, TYPE>
  1525.  
  1526. template<class BASE_CLASS, class TYPE>
  1527. class CTypedPtrArray : public BASE_CLASS
  1528. {
  1529. public:
  1530.     // Accessing elements
  1531.     TYPE GetAt(int nIndex) const
  1532.         { return (TYPE)BASE_CLASS::GetAt(nIndex); }
  1533.     TYPE& ElementAt(int nIndex)
  1534.         { return (TYPE&)BASE_CLASS::ElementAt(nIndex); }
  1535.     void SetAt(int nIndex, TYPE ptr)
  1536.         { BASE_CLASS::SetAt(nIndex, ptr); }
  1537.  
  1538.     // Potentially growing the array
  1539.     void SetAtGrow(int nIndex, TYPE newElement)
  1540.        { BASE_CLASS::SetAtGrow(nIndex, newElement); }
  1541.     int Add(TYPE newElement)
  1542.        { return BASE_CLASS::Add(newElement); }
  1543.     int Append(const CTypedPtrArray<BASE_CLASS, TYPE>& src)
  1544.        { return BASE_CLASS::Append(src); }
  1545.     void Copy(const CTypedPtrArray<BASE_CLASS, TYPE>& src)
  1546.         { BASE_CLASS::Copy(src); }
  1547.  
  1548.     // Operations that move elements around
  1549.     void InsertAt(int nIndex, TYPE newElement, int nCount = 1)
  1550.         { BASE_CLASS::InsertAt(nIndex, newElement, nCount); }
  1551.     void InsertAt(int nStartIndex, CTypedPtrArray<BASE_CLASS, TYPE>* pNewArray)
  1552.        { BASE_CLASS::InsertAt(nStartIndex, pNewArray); }
  1553.  
  1554.     // overloaded operator helpers
  1555.     TYPE operator[](int nIndex) const
  1556.         { return (TYPE)BASE_CLASS::operator[](nIndex); }
  1557.     TYPE& operator[](int nIndex)
  1558.         { return (TYPE&)BASE_CLASS::operator[](nIndex); }
  1559. };
  1560.  
  1561. /////////////////////////////////////////////////////////////////////////////
  1562. // CTypedPtrList<BASE_CLASS, TYPE>
  1563.  
  1564. template<class BASE_CLASS, class TYPE>
  1565. class _CTypedPtrList : public BASE_CLASS
  1566. {
  1567. public:
  1568. // Construction
  1569.     _CTypedPtrList(int nBlockSize = 10)
  1570.         : BASE_CLASS(nBlockSize) { }
  1571.  
  1572.     // peek at head or tail
  1573.     TYPE& GetHead()
  1574.         { return (TYPE&)BASE_CLASS::GetHead(); }
  1575.     TYPE GetHead() const
  1576.         { return (TYPE)BASE_CLASS::GetHead(); }
  1577.     TYPE& GetTail()
  1578.         { return (TYPE&)BASE_CLASS::GetTail(); }
  1579.     TYPE GetTail() const
  1580.         { return (TYPE)BASE_CLASS::GetTail(); }
  1581.  
  1582.     // get head or tail (and remove it) - don't call on empty list!
  1583.     TYPE RemoveHead()
  1584.         { return (TYPE)BASE_CLASS::RemoveHead(); }
  1585.     TYPE RemoveTail()
  1586.         { return (TYPE)BASE_CLASS::RemoveTail(); }
  1587.  
  1588.     // iteration
  1589.     TYPE& GetNext(POSITION& rPosition)
  1590.         { return (TYPE&)BASE_CLASS::GetNext(rPosition); }
  1591.     TYPE GetNext(POSITION& rPosition) const
  1592.         { return (TYPE)BASE_CLASS::GetNext(rPosition); }
  1593.     TYPE& GetPrev(POSITION& rPosition)
  1594.         { return (TYPE&)BASE_CLASS::GetPrev(rPosition); }
  1595.     TYPE GetPrev(POSITION& rPosition) const
  1596.         { return (TYPE)BASE_CLASS::GetPrev(rPosition); }
  1597.  
  1598.     // getting/modifying an element at a given position
  1599.     TYPE& GetAt(POSITION position)
  1600.         { return (TYPE&)BASE_CLASS::GetAt(position); }
  1601.     TYPE GetAt(POSITION position) const
  1602.         { return (TYPE)BASE_CLASS::GetAt(position); }
  1603.     void SetAt(POSITION pos, TYPE newElement)
  1604.         { BASE_CLASS::SetAt(pos, newElement); }
  1605. };
  1606.  
  1607. template<class BASE_CLASS, class TYPE>
  1608. class CTypedPtrList : public _CTypedPtrList<BASE_CLASS, TYPE>
  1609. {
  1610. public:
  1611. // Construction
  1612.     CTypedPtrList(int nBlockSize = 10)
  1613.         : _CTypedPtrList<BASE_CLASS, TYPE>(nBlockSize) { }
  1614.  
  1615.     // add before head or after tail
  1616.     POSITION AddHead(TYPE newElement)
  1617.         { return BASE_CLASS::AddHead(newElement); }
  1618.     POSITION AddTail(TYPE newElement)
  1619.         { return BASE_CLASS::AddTail(newElement); }
  1620.  
  1621.     // add another list of elements before head or after tail
  1622.     void AddHead(CTypedPtrList<BASE_CLASS, TYPE>* pNewList)
  1623.         { BASE_CLASS::AddHead(pNewList); }
  1624.     void AddTail(CTypedPtrList<BASE_CLASS, TYPE>* pNewList)
  1625.         { BASE_CLASS::AddTail(pNewList); }
  1626. };
  1627.  
  1628. // need specialized version for CObList because of AddHead/Tail ambiguity
  1629. template<> class CTypedPtrList<CObList, CObList*> 
  1630.     : public _CTypedPtrList<CObList, CObList*>
  1631. {
  1632. public:
  1633. // Construction
  1634.     CTypedPtrList(int nBlockSize = 10)
  1635.         : _CTypedPtrList<CObList, CObList*>(nBlockSize) { }
  1636.  
  1637.     // add before head or after tail
  1638.     POSITION AddHead(TYPE newElement)
  1639.         { return _CTypedPtrList<CObList, CObList*>::AddHead((CObject*)newElement); }
  1640.     POSITION AddTail(TYPE newElement)
  1641.         { return _CTypedPtrList<CObList, CObList*>::AddTail((CObject*)newElement); }
  1642.  
  1643.     // add another list of elements before head or after tail
  1644.     void AddHead(CTypedPtrList<BASE_CLASS, TYPE>* pNewList)
  1645.         { _CTypedPtrList<CObList, CObList*>::AddHead(pNewList); }
  1646.     void AddTail(CTypedPtrList<BASE_CLASS, TYPE>* pNewList)
  1647.         { _CTypedPtrList<CObList, CObList*>::AddTail(pNewList); }
  1648. };
  1649.  
  1650. // need specialized version for CPtrList because of AddHead/Tail ambiguity
  1651. template<> class CTypedPtrList<CPtrList, CPtrList*> 
  1652.     : public _CTypedPtrList<CPtrList, CPtrList*>
  1653. {
  1654. public:
  1655. // Construction
  1656.     CTypedPtrList(int nBlockSize = 10)
  1657.         : _CTypedPtrList<CPtrList, CPtrList*>(nBlockSize) { }
  1658.  
  1659.     // add before head or after tail
  1660.     POSITION AddHead(TYPE newElement)
  1661.         { return _CTypedPtrList<CPtrList, CPtrList*>::AddHead((void*)newElement); }
  1662.     POSITION AddTail(TYPE newElement)
  1663.         { return _CTypedPtrList<CPtrList, CPtrList*>::AddTail((void*)newElement); }
  1664.  
  1665.     // add another list of elements before head or after tail
  1666.     void AddHead(CTypedPtrList<BASE_CLASS, TYPE>* pNewList)
  1667.         { _CTypedPtrList<CPtrList, CPtrList*>::AddHead(pNewList); }
  1668.     void AddTail(CTypedPtrList<BASE_CLASS, TYPE>* pNewList)
  1669.         { _CTypedPtrList<CPtrList, CPtrList*>::AddTail(pNewList); }
  1670. };
  1671.  
  1672. /////////////////////////////////////////////////////////////////////////////
  1673. // CTypedPtrMap<BASE_CLASS, KEY, VALUE>
  1674.  
  1675. template<class BASE_CLASS, class KEY, class VALUE>
  1676. class CTypedPtrMap : public BASE_CLASS
  1677. {
  1678. public:
  1679.  
  1680. // Construction
  1681.     CTypedPtrMap(int nBlockSize = 10)
  1682.         : BASE_CLASS(nBlockSize) { }
  1683.  
  1684.     // Lookup
  1685.     BOOL Lookup(BASE_CLASS::BASE_ARG_KEY key, VALUE& rValue) const
  1686.         { return BASE_CLASS::Lookup(key, (BASE_CLASS::BASE_VALUE&)rValue); }
  1687.  
  1688.     // Lookup and add if not there
  1689.     VALUE& operator[](BASE_CLASS::BASE_ARG_KEY key)
  1690.         { return (VALUE&)BASE_CLASS::operator[](key); }
  1691.  
  1692.     // add a new key (key, value) pair
  1693.     void SetAt(KEY key, VALUE newValue)
  1694.         { BASE_CLASS::SetAt(key, newValue); }
  1695.  
  1696.     // removing existing (key, ?) pair
  1697.     BOOL RemoveKey(KEY key)
  1698.         { return BASE_CLASS::RemoveKey(key); }
  1699.  
  1700.     // iteration
  1701.     void GetNextAssoc(POSITION& rPosition, KEY& rKey, VALUE& rValue) const
  1702.         { BASE_CLASS::GetNextAssoc(rPosition, (BASE_CLASS::BASE_KEY&)rKey,
  1703.             (BASE_CLASS::BASE_VALUE&)rValue); }
  1704. };
  1705.  
  1706. /////////////////////////////////////////////////////////////////////////////
  1707.  
  1708. #undef THIS_FILE
  1709. #define THIS_FILE __FILE__
  1710.  
  1711. #undef new
  1712. #ifdef _REDEF_NEW
  1713. #define new DEBUG_NEW
  1714. #undef _REDEF_NEW
  1715. #endif
  1716.  
  1717. #ifdef _AFX_PACKING
  1718. #pragma pack(pop)
  1719. #endif
  1720.  
  1721. #ifdef _AFX_MINREBUILD
  1722. #pragma component(minrebuild, on)
  1723. #endif
  1724. #ifndef _AFX_FULLTYPEINFO
  1725. #pragma component(mintypeinfo, off)
  1726. #endif
  1727.  
  1728. #endif //__AFXTEMPL_H__
  1729.  
  1730. /////////////////////////////////////////////////////////////////////////////
  1731.